#pragma once

#include <iostream>
#include <queue>
#include <vector>
#include <unistd.h>
#include "localmutex.hpp"
#include "localcond.hpp"
#include "localsem.hpp"

namespace Local_Prod_Cons_Mod
{
    template <typename T>
    class LocalRingQueue
    {
    public:
        // 构造函数
        LocalRingQueue(int capacity)
            : _capacity(capacity), _prodindex(0), _consindex(0), _prodsem(capacity), _conssem(0)
        {
            _ringqueue.resize(_capacity);
        }
        ~LocalRingQueue() = default;
        // 拷贝构造
        LocalRingQueue(const LocalRingQueue<T> &cpy) = delete;
        // 赋值重载
        LocalRingQueue operator=(const LocalRingQueue<T> &cpy) = delete;
        // 生产者
        void Push(T *t)
        {
            // 1.生产者P操作
            _prodsem.P();
            { // 加锁
                Local_Mutex::LockGuard prodlock(&_prodmutex);
                // 2.放入数据
                _ringqueue[_prodindex] = *t;
                // 3.下标更新
                ++_prodindex;
                // 4.保持环形队列
                _prodindex %= _capacity;
            } // 解锁
            // 5.消费者V操作
            _conssem.V();
        }
        // 消费者
        T Pop()
        {
            T t;
            // 1.消费者P操作
            _conssem.P();
            { // 加锁
                Local_Mutex::LockGuard conslock(&_consmutex);
                // 2.拿出数据
                t = _ringqueue[_consindex];
                // 3.下标更新
                ++_consindex;
                // 4.保持环形队列
                _consindex %= _capacity;
            } // 解锁
            // 5.生产者V操作
            _prodsem.V();
            return t;
        }

    private:
        std::vector<T> _ringqueue; // 环形队列
        int _capacity;             // 容量

        int _prodindex; // 生产者数组下标
        int _consindex; // 消费者数组下标

        Local_Sem::LocalSem _prodsem; // 生产者信号量
        Local_Sem::LocalSem _conssem; // 消费者信号量

        Local_Mutex::LocalMutex _prodmutex; // 生产者互斥量
        Local_Mutex::LocalMutex _consmutex; // 消费者互斥量
    };
}

namespace Local_Prod_Cons_Mod
{
    template <typename T>
    class LocalBlockQueue
    {
    private:
        bool IsFull()
        {
            return _blockqueue.size() == _capacity;
        }
        bool IsEmpty()
        {
            return _blockqueue.empty();
        }

    public:
        // 构造函数
        LocalBlockQueue(int capacity)
            : _capacity(capacity), _prodwaitnum(0), _conswaitnum(0)
        {
        }
        // 析构函数
        ~LocalBlockQueue()
        {
        }
        // 拷贝构造
        LocalBlockQueue(const LocalBlockQueue<T> &cpy) = delete;
        // 赋值重载
        LocalBlockQueue operator=(const LocalBlockQueue<T> &cpy) = delete;

        // 生产
        void Push(T *pt)
        {
            {
                // 1.竞争锁
                Local_Mutex::LockGuard lockguard(&_mutex);
                // 2.循环判断队列是否放满
                while (IsFull())
                {
                    // 等待挂起
                    _prodwaitnum++;
                    _prodcond.Wait(&(_mutex._mutex));
                    _prodwaitnum--;
                }
                // 3.入队列
                _blockqueue.push(*pt);
                // 4.唤醒消费者
                if (_conswaitnum > 0)
                {
                    _conscond.Signal();
                }
                // 5.释放锁
            }
        }
        // 消费
        T Pop()
        {
            // 此处要求传自定义类型的时候需要提供默认构造
            T t;
            {
                // 1.竞争锁
                Local_Mutex::LockGuard lockguard(&_mutex);
                // 2.循环判断队列是否为空
                while (IsEmpty())
                {
                    // 等待挂起
                    _conswaitnum++;
                    _conscond.Wait(&(_mutex._mutex));
                    _conswaitnum--;
                }
                // 3.出队列
                // 此处要求传自定义类型的时候需要提供赋值重载
                t = _blockqueue.front();
                _blockqueue.pop();
                // 4.唤醒生产者
                if (_prodwaitnum > 0)
                {
                    _prodcond.Signal();
                }
                // 5.释放锁
            }
            return t;
        }

    private:
        std::queue<T> _blockqueue; // 阻塞队列
        int _capacity;             // 容量

        Local_Mutex::LocalMutex _mutex;  // 互斥量
        Local_Cond::LocalCond _prodcond; // 生产者条件变量
        Local_Cond::LocalCond _conscond; // 消费者条件变量

        int _prodwaitnum; // 生产者等待数量
        int _conswaitnum; // 消费者等待数量
    };
}
